/******************************************************************************
*
* This file is part of FreeTrack (http://code.google.com/p/qtfreetrack).
* BY Willy Gardiol (willy@gardiol.org)
*
* FreeTrack is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTrack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/
#include "tracktable.h"

#include "livetrack.h"
#include "tracksmanager.h"
#include "mapsmanager.h"
#include "ftpainter.h"

#include "controls/ftlabel.h"
#include "controls/ftpushbuttonicon.h"
#include "controls/ftmessagebox.h"
#include "controls/ftcompass.h"
#include "controls/ftslidebutton.h"
#include "controls/ftlatlonedit.h"
#include "controls/fttextarea.h"

// Say here how many degrees shall map to the screen width at startup
#define INITIAL_WIDTH 0.01
// Zoom steps... (original is: 10 / 20 for extra zoom)
#define SCALE_STEPS 10
#define SCALE_START_STEP 7

// Three "decluttering" modes on the screen:
// 1 - only basic stuff (zoom, position) visible on screen
#define SIMPLE_MODE 1
// 2 - all the nvaigation stuff (buttons and drawings) are visible
#define NAV_MODE 2
// 3 - everything is visible
#define FULL_MODE 3

TrackTable::TrackTable(const TracksManager * l,
                       LiveTrack* lt,
                       const MapsManager* mp) :
    QWidget(),
    gps_has_fix( GpsManager::no_fix ),
    screen_scale( 360.0/INITIAL_WIDTH ),
    zoom_step(SCALE_START_STEP)
{
    tracks = l;
    current_speed = current_steepness = 0.0;
    livetrack = lt;
    maps = mp;
    currentBearing = 0.0;
    destination_distance = 0;

    proximity_threeshold = configuration->navigationProximity();
    connect( configuration, SIGNAL(navigationProximityChanged(int)),
             this, SLOT(updateProximity(int)) );

    // Initialize some internal stuff
    longitude_correction = 1.0;
    current_mode = FULL_MODE;

    // Read the initial position from the configuration
    configuration->initialPosition( screen_latitude,
                                    screen_longitude,
                                    screen_altitude );
    // And set it as the last known GPS position
    gps_position.setLatitude( screen_latitude );
    gps_position.setLongitude( screen_longitude );
    gps_position.setAltitude( screen_altitude );

    // On startup navigation is always disabled:
    navigationEnabled = false;

    // Initialize the map display:
    drawMaps = configuration->showMapsOnStartup();

    // Build the controls
    buildCommonWidgets();
    buildNavigationWidgets();
    buildFullWidgets();

    // We store some default sizes to speed up during resize and redraws
    button_width = FTControls::iconSize( FTControls::IconBig ).width();
    button_height = FTControls::iconSize( FTControls::IconBig ).height();

    updateAltitude( screen_altitude );
    updateLatLon( screen_latitude, screen_longitude );
}

TrackTable::~TrackTable()
{
}

void TrackTable::updateProximity(int p)
{
    proximity_threeshold = p;
}

void TrackTable::buildCommonWidgets()
{    
    // Create zoom buttons
    zoomInButton = new FTPushButtonIcon(QIcon(":/table/zoom_in.png"),
                                    FTControls::IconBig,
                                    this);
    connect( zoomInButton, SIGNAL(clicked()),
             this, SLOT(zoomIn()));
    zoomOutButton = new FTPushButtonIcon(QIcon(":/table/zoom_out.png"),
                                    FTControls::IconBig,
                                    this);
    connect( zoomOutButton, SIGNAL(clicked()),
             this, SLOT(zoomOut()));
    // Create the zoom meter pixmaps and resize them
    zoomMeterPixmap = QPixmap( ":/table/zoom_meter.png");
    zoomMeterPixmap = zoomMeterPixmap.scaled( FTControls::adjustSize(zoomMeterPixmap.size() ) );
    zoomMarkerPixmap = QPixmap( ":/table/zoom_marker.png");
    zoomMarkerPixmap = zoomMarkerPixmap.scaled( FTControls::adjustSize(zoomMarkerPixmap.size() ) );


    // Create the mode slider "declutter" button
    modeButton = new FTSlideButton( Qt::Horizontal,
                                    FTControls::IconNormal,
                                    this);
    modeButton->addState(SIMPLE_MODE, QIcon(":/table/simple_mode.png"));
    modeButton->addState(NAV_MODE, QIcon(":/table/nav_mode.png"));
    modeButton->addState(FULL_MODE, QIcon(":/table/full_mode.png"));
    modeButton->setState( current_mode );
    connect( modeButton, SIGNAL(stateSet(int)),
             this, SLOT(setMode(int)));

    // The central screen cross
    centerPixmap = QPixmap( ":/table/cross.png" ).scaled( FTControls::iconSize( FTControls::IconNormal ) );

    // Create lat/lon edit and labels
    latLonLabel = new FTLatLonEdit( screen_latitude,
                                    screen_longitude,
                                    Qt::Vertical,
                                    this);
    latLonLabel->setBackgroundStyle( Qt::Dense2Pattern );

    connect( latLonLabel, SIGNAL(updated(double,double)),
             this, SLOT(updateLatLon(double,double)) );
}

void TrackTable::buildNavigationWidgets()
{
    // Add new waypoint..
    waypoint = new FTPushButtonIcon(QIcon(":/table/waypoint.png"),
                                    FTControls::IconBig,
                                    this);
    connect( waypoint, SIGNAL(clicked()), this, SLOT(addWaypoint()));

    // Create follow gps button...
    follow = new FTPushButtonIcon( QIcon(":/table/mirino.png"),
                                   FTControls::IconBig,
                                   this);
    // We start in follow mode, always, at startup.
    follow->setCheckable(true);
    follow->setChecked(true);

    // Stop navigation button...
    stopNavigationButton = new FTPushButtonIcon( QIcon(":/table/stop_follow.png"),
                                                 FTControls::IconBig,
                                                 this);
    // ... is disabled at startup...
    stopNavigationButton->hide();
    connect( stopNavigationButton, SIGNAL(clicked()),
             this, SLOT(stopNavigation()) );
    connect( follow, SIGNAL(clicked()), this, SLOT(followMode()));

    // Create compass
    if ( configuration->compassAvailable() )
    {
        compass = new FTCompass( FTControls::IconBig,
                                 this);
        connect( compass, SIGNAL(bearingChange(qreal)),
                 this, SLOT(bearingUpdate(qreal)));
    }
    else
        compass = NULL;

    // Altitude label
    altitudeLabel = new FTTextArea("", 3, this);
    altitudeLabel->setWordWrap(false);
    altitudeLabel->setAlignment( Qt::AlignCenter );
    altitudeLabel->setBackgroundStyle( Qt::Dense2Pattern );

    gpsPositionPixmap = QPixmap(":/table/pin_red.png");
    gpsPositionPixmap = gpsPositionPixmap.scaled( FTControls::adjustSize(gpsPositionPixmap.size() ) );

    gpsPosNoFixPixmap = QPixmap(":/table/pin_red_nofix.png");
    gpsPosNoFixPixmap = gpsPosNoFixPixmap.scaled( FTControls::adjustSize(gpsPosNoFixPixmap.size() ) );

    comeHerePixmap = QPixmap(":/table/come_here.png");
    comeHerePixmap = comeHerePixmap.scaled( FTControls::adjustSize(comeHerePixmap.size() ) );
    comeHereOffset = QPoint( comeHerePixmap.width() / 2,
                             comeHerePixmap.height()/2 );

    gps_pin_offset = QPoint( gpsPositionPixmap.width()/2, gpsPositionPixmap.height()/2 );
    bearingHandPoly = QPolygon();
    bearingHandPoly << QPoint(5, -8)
                    << QPoint(-5, -8)
                    << QPoint(0, -50);

    navigationHandPoly = QPolygon();
    navigationHandPoly << QPoint(3, 8)
                       << QPoint(3, -15)
                       << QPoint(10, -15)
                       << QPoint(0, -25)
                       << QPoint(-10, -15)
                       << QPoint(-3, -15)
                       << QPoint(-3, 8);
}

void TrackTable::buildFullWidgets()
{
    startTrackButton = new FTPushButtonIcon( QIcon(":/livetrack/start_tracking.png"),
                                             FTControls::IconBig,
                                             this);
    connect( startTrackButton, SIGNAL(clicked()),
             this, SIGNAL(toggleTracking()));

    enableMapsButton = new FTPushButtonIcon( QIcon(":/statusbar/maps_on.png"),
                                             FTControls::IconBig,
                                             this);
    if ( !drawMaps )
        enableMapsButton->setIcon( QIcon(":/statusbar/maps_off.png") );
    connect( enableMapsButton, SIGNAL(clicked()),
             this, SIGNAL(toggleMaps()));

    QIcon gps_icon = configuration->gpsAutostart() ? QIcon(":/statusbar/gps_nofix.png") :
                                                     QIcon(":/statusbar/gps_disabled.png");
    enableGpsButton = new FTPushButtonIcon( gps_icon,
                                             FTControls::IconBig,
                                             this);
    connect( enableGpsButton, SIGNAL(clicked()),
             this, SIGNAL(toggleGps()));
}

void TrackTable::bearingUpdate(qreal b)
{
    currentBearing = b;
    update();
}

void TrackTable::resizeEvent(QResizeEvent * ev)
{
    // When resizing, we need to reposition all the widgets on the screen...
    // So first call the widget resize handler...
    QWidget::resizeEvent(ev);

    // Quickies to store screen sizes
    int screen_width = width();
    int screen_height = height();

    // Ensure the widgets have a valid size (since we do not use layouts...)
    // (this is required only on the first time, but it does not hurt to redo it)
    altitudeLabel->resize( altitudeLabel->sizeHint() );
    latLonLabel->resize( latLonLabel->sizeHint() );
    modeButton->resize( modeButton->sizeHint() );
    if ( compass != NULL )
        compass->resize( compass->sizeHint() );

    if ( height() > width() ) // portrait mode
    {
        // Simple mode:
        // Zoom controls: centered on the left border
        int zoom_meter_height = zoomMeterPixmap.height();
        zoom_start_y = (screen_height - (button_height*2 + zoom_meter_height)) / 2;
        zoomOutButton->move(0, zoom_start_y );
        zoomInButton->move(0, zoom_start_y + button_height + zoom_meter_height);
        // Mode selection is centerd on the top border:
        modeButton->move( (screen_width - modeButton->width())/2, 0 );
        // Present position is at bottom-left corner:
        latLonLabel->move( 0, screen_height - latLonLabel->height() );

        // Navigation mode:

        // Top left corner:
        follow->move( 0,0 );
        // Below the three full controls icons
        waypoint->move( screen_width - button_width,
                        button_height*3 );
        stopNavigationButton->move( screen_width - button_width,
                                    button_height*4);
        // Altitude is on right border, below waypoint icon
        altitudeLabel->move( screen_width - altitudeLabel->width(),
                             button_height*5 );
        // Compass, if present, is at bottom-right corner:
        if ( compass != NULL )
            compass->move(screen_width - compass->width(),
                          screen_height - compass->height() );

        // Full controls mode:
        // These buttons are located on the top-right corner and top-left corner:
        enableMapsButton->move( screen_width - button_width,
                                0 );
        enableGpsButton->move( screen_width - button_width,
                                button_height );
        startTrackButton->move( screen_width - button_width,
                                button_height*2 );
    }
    else // landscape mode
    {
        // Simple mode:
        // Zoom controls: centered on the left border
        int zoom_meter_height = zoomMeterPixmap.height();
        zoom_start_y = (screen_height - (button_height*2 + zoom_meter_height)) / 2;
        zoomOutButton->move(0, zoom_start_y );
        zoomInButton->move(0, zoom_start_y + button_height + zoom_meter_height);
        // Mode selection is centerd on the top border:
        modeButton->move( button_width*2, 0 );
        // Present position is at middle of bottom border:
        latLonLabel->move( button_width,
                           screen_height - latLonLabel->height() );

        // Navigation mode:
        // Top left corner:
        follow->move( button_width,0 );
        // Mid of right border
        waypoint->move( screen_width - button_width *2,
                       screen_height-button_height);
        stopNavigationButton->move( screen_width - button_width,
                                    screen_height/2 + button_height);
        // Altitude is right of position:
        altitudeLabel->move(latLonLabel->width() + button_width,
                            screen_height - altitudeLabel->height() );
        // Compass, if present, is at bottom-right corner:
        if ( compass != NULL )
            compass->move(screen_width - compass->width(),
                          screen_height - compass->height() );

        // Full controls mode:
        // These buttons are located on the top border:
        enableMapsButton->move( screen_width-button_width,
                                0 );
        enableGpsButton->move( screen_width-button_width,
                                button_height );
        startTrackButton->move( screen_width-button_width,
                                button_height*2 );
    }
    updateMatrix();
}

void TrackTable::mapsEnabled(bool e)
{
    drawMaps = e;
    if ( e )
        enableMapsButton->setIcon( QIcon(":/statusbar/maps_on.png") );
    else
        enableMapsButton->setIcon( QIcon(":/statusbar/maps_off.png") );
    update();
}

void TrackTable::livetrackRecording(bool e)
{
    if ( e )
        startTrackButton->setIcon( QIcon(":/livetrack/stop_tracking.png") );
    else
        startTrackButton->setIcon( QIcon(":/livetrack/start_tracking.png") );
}

void TrackTable::addWaypoint()
{
    livetrack->createWaypoint( screen_latitude,
                               screen_longitude,
                               screen_altitude );
}

void TrackTable::paintEvent ( QPaintEvent *)
{
    // Create the painter and set paint mode
    FTPainter painter( this );
    painter.fillRect( rect(), QColor("black") );

    // Fix a bug in Symbian (at least for Qt 4.6.3)
    painter.setBackgroundMode ( Qt::OpaqueMode );

    // this is the ORIGINAL size, in pixels, of the tracking table.
    int screen_width = width();
    int screen_height = height();

    // HERE STARTS THE ACTUAL DRAWING

    // Draw the maps...
    if ( drawMaps )
        maps->paintMap( painter,
                        wgs84_to_screen_matrix,
                        wgs84_visible_rect,
                        screen_scale,
                        screen_scale*longitude_correction );

    // Draw the tracks...
    foreach ( int i, tracks->listTracks() )
    {
        const GPS_track* trk = tracks->trackPtr(i);
        if ( trk )
            painter.drawTrack( *trk, wgs84_to_screen_matrix, wgs84_visible_rect );
    }
    // Draw the LiveTrack...
    painter.drawTrack( *(livetrack->track()), wgs84_to_screen_matrix, wgs84_visible_rect );

    // Draw the current GPS point (or the last good one)
    QString dest_dist = "";
    // We always draw the "i am here" stuff, but we use a different pixmap if there is fix or not
    QPoint gpsPt = (QPointF(gps_position.longitude(),
                            gps_position.latitude()) * wgs84_to_screen_matrix).toPoint();

    painter.save();
    painter.setPen( QPen( QBrush( QColor(255,255,255) ), 2) );
    painter.setBrush( QBrush( QColor(0,0,0) ) );
    painter.translate( gpsPt );
    if ( compass != NULL )
    {
        painter.rotate( currentBearing );
        painter.drawConvexPolygon( bearingHandPoly );
    }

    if ( gps_has_fix == GpsManager::fix )
        painter.drawPixmap( -gps_pin_offset, gpsPositionPixmap );
    else
        painter.drawPixmap( -gps_pin_offset, gpsPosNoFixPixmap );
    painter.restore();

    // Draw navigation stuff, but only if NOT in simple mode...
    if ( navigationEnabled && (current_mode != SIMPLE_MODE) )
    {
        if ( destination_distance > 1000 )
            dest_dist = QString("%1Km").arg( destination_distance/1000 );
        else
            dest_dist = QString("%1m").arg( destination_distance );

        painter.save();
        painter.translate( gpsPt );
        QPoint destpt = ( QPointF( destination.longitude(), destination.latitude() ) * wgs84_to_screen_matrix).toPoint();
        destpt.setX( destpt.x() - gpsPt.x() );
        destpt.setY( destpt.y() - gpsPt.y() );
        double andgolo = atan2( (double)destpt.x(), (double)destpt.y() ) * 180.0 / 3.14159265;

        painter.setPen( QPen( QBrush( QColor(255,0,0)), 2, Qt::DashDotLine) );
        painter.drawLine( QPoint(0,0), destpt );
        QPoint comeHerePt = destpt - comeHereOffset;
        painter.drawPixmap( comeHerePt, comeHerePixmap );
        painter.save();
        painter.rotate( 180.0-andgolo );
        painter.setPen( QPen( QBrush( QColor(255,255,255) ), 2) );
        painter.setBrush( QBrush( QColor(255,0,0) ) );
        painter.drawConvexPolygon( navigationHandPoly );
        painter.restore();
        painter.drawText( 0,0, dest_dist );
        painter.restore();
    }

    // Now draw the "static" stuff (lines and various pixmaps)
    int half_screen_width = screen_width / 2;
    int half_screen_height = screen_height / 2;
    int step = qMin( screen_width, screen_height ) / 5;

    // Draw the grid on screen
    painter.setPen( QPen( QBrush( QColor(128,128,128) ), 0) );
    for ( int x = half_screen_width; x > 0; x -= step)
        painter.drawLine( QLine( x, 0, x, screen_height));
    for ( int x = half_screen_width; x < screen_width; x += step)
        painter.drawLine( QLine( x, 0, x, screen_height));
    for ( int y = half_screen_height; y > 0; y -= step)
        painter.drawLine( QLine( 0, y, screen_width, y));
    for ( int y = half_screen_height; y < screen_height; y += step)
        painter.drawLine( QLine( 0, y, screen_width, y));

    // Draw the "cross" in the middle of the screen
    painter.drawPixmap( half_screen_width-centerPixmap.width()/2,
                        half_screen_height-centerPixmap.height()/2,
                        centerPixmap );

    // Draw the "zoom" meter
    painter.drawPixmap( (button_width-zoomMeterPixmap.width())/2,
                        zoom_start_y + button_height,
                        zoomMeterPixmap );
    painter.drawPixmap( (button_width-zoomMeterPixmap.width())/2,
                        zoom_start_y +
                        button_height +
                        zoom_step*zoomMeterPixmap.height()*0.9 / SCALE_STEPS +
                        2,
                        zoomMarkerPixmap );

}

void TrackTable::reachedDestination()
{
    emit destinationReached();
}

void TrackTable::zoomIn()
{
    if ( zoom_step < SCALE_STEPS )
    {
        screen_scale *= 2;
        zoom_step++;
        updateMatrix();
    }
}

void TrackTable::zoomOut()
{
   if ( zoom_step > 0 )
    {
        screen_scale /= 2.0;
        zoom_step--;
        updateMatrix();
    }
}

void TrackTable::startNavigation( QGeoCoordinate c )
{
    destination = c;
    destination_distance = destination.distanceTo( gps_position );
    stopNavigationButton->show();
    navigationEnabled = true;
}

void TrackTable::stopNavigation()
{
    navigationEnabled = false;
    stopNavigationButton->hide();
    update();
    emit navigationStopped();
}

void TrackTable::gpsUpdated(GPS_point new_pt)
{   // Store locally the GPS position
    gps_position = new_pt;
    current_speed = new_pt.speed();
    current_steepness =  new_pt.steepness();

    if ( navigationEnabled )
    {
        destination_distance = destination.distanceTo( gps_position );
        if (destination_distance <= proximity_threeshold )
            reachedDestination();
    }
    // Update current position, if required
    followMode();
}

void TrackTable::gpsStatusChanged(GpsManager::gps_status gps_status)
{
    gps_has_fix = gps_status;
    if ( gps_has_fix == GpsManager::fix )
        enableGpsButton->setIcon( QIcon(":/statusbar/gps_fix.png") );
    else if ( gps_has_fix == GpsManager::no_fix)
        enableGpsButton->setIcon( QIcon(":/statusbar/gps_nofix.png") );
    else
        enableGpsButton->setIcon( QIcon(":/statusbar/gps_disabled.png") );
}

void TrackTable::followMode()
{
    // If we are in "follow" mode, we need to update the screen_center
    if ( follow->isChecked() )
    {
        double tmp_lat = 0.0,
                tmp_lon = 0.0,
                tmp_alt = 0.0;
        // If we have a GPS update, use it.
        if ( gps_has_fix == GpsManager::fix )
        {
            tmp_lon = gps_position.longitude();
            tmp_lat = gps_position.latitude();
            tmp_alt = gps_position.altitude();
        }
        // Otherwise, use Live Track last point.
        else
        {
            const GPS_point* last_pt = livetrack->lastPoint();
            if ( last_pt != NULL )
            {
                tmp_lon = last_pt->longitude();
                tmp_lat = last_pt->latitude();
                tmp_alt = last_pt->altitude();
            }
            else // Use configuration default start point
            {
                int int_tmp_alt;
                configuration->initialPosition( tmp_lat,
                                                tmp_lon,
                                                int_tmp_alt );
                tmp_alt = int_tmp_alt;
            }
        }
        updateAltitude( tmp_alt );
        updateLatLon( tmp_lat, tmp_lon );
        configuration->setInitialPosition( tmp_lat,
                                           tmp_lon,
                                           (int)tmp_alt );
    }
    else
        update();
}

void TrackTable::mousePressEvent ( QMouseEvent * event )
{
    mouse_start = event->posF();
    follow->setChecked(false);
}

void TrackTable::mouseReleaseEvent ( QMouseEvent * event )
{
    double tmp_lat, tmp_lon;
    QPointF curr_pos = event->posF();
    tmp_lat = screen_latitude -(mouse_start.y()-curr_pos.y()) / screen_scale;
    tmp_lon = screen_longitude + (mouse_start.x()-curr_pos.x()) / (screen_scale * longitude_correction);
    updateLatLon( tmp_lat, tmp_lon );
}

void TrackTable::mouseMoveEvent ( QMouseEvent * event )
{
    mouseReleaseEvent(event);
    mouse_start = event->posF();
}

void TrackTable::setMode(int m)
{
    current_mode = m;
    if ( current_mode == SIMPLE_MODE )
    {
        toggleNavigation(false);
        toggleFull(false);
    }
    else if ( current_mode == NAV_MODE )
    {
        toggleNavigation(true);
        toggleFull(false);
    }
    else if ( current_mode == FULL_MODE )
    {
        toggleNavigation(true);
        toggleFull(true);
    }
    update();
}

void TrackTable::toggleNavigation(bool show)
{
    follow->setVisible( show );
    waypoint->setVisible( show );
    stopNavigationButton->setVisible( show && navigationEnabled );
    altitudeLabel->setVisible( show );
    if ( compass != NULL )
        compass->setVisible( show );
}

void TrackTable::toggleFull(bool show)
{
    startTrackButton->setVisible( show );
    enableMapsButton->setVisible( show );
    enableGpsButton->setVisible( show );
}

void TrackTable::updateLatLon(double lat, double lon)
{
    screen_latitude = lat;
    screen_longitude = lon;
    // Since we do a very simply projection we need to compensate for the fact that
    // longitude do shrink towards the poles.
    // (scale differently longitude 0 : 111km, 40 : 85km, 90 = 0km; y = -26/40*x + 111)
    // % at 45lat = 73%
    static double old_correction = -1;
    longitude_correction = (-26.0*screen_latitude/40.0+111.0)/111.0;
    // Dont let the correction change more than 0.01, to avoid "fluctuating" values...
    if ( (old_correction == -1) || ( fabs(longitude_correction - old_correction) > 0.01 ) )
        old_correction = longitude_correction;
    else
        longitude_correction = old_correction;

    latLonLabel->setLatLon( lat, lon );
    updateMatrix();
}

void TrackTable::updateAltitude(double alt)
{
    screen_altitude = alt;
    QString speed = "--";
    QString steep = "--";
    QString altStr = tr("Alt");
    QString spdStr = tr("Spd");
    QString stpStr = tr("Stp");
    if ( gps_has_fix )
    {
        if ( current_speed != 0.0 )
            speed = QString("%1").arg( current_speed*3.6, 0, 'f',2 );
        if ( current_steepness != 0.0 )
            steep = QString("%1").arg( current_steepness, 0, 'f',2 );
    }
    altitudeLabel->setText( QString("%1:%2mt\n%3:%4km/h\n%5:%6%")
                            .arg( altStr )
                            .arg((int)screen_altitude)
                            .arg(spdStr)
                            .arg(speed)
                            .arg(stpStr)
                            .arg(steep) );
    altitudeLabel->resize( altitudeLabel->sizeHint() );

    if ( height() > width() ) // portrait mode
    {
        altitudeLabel->move( width() - altitudeLabel->width(),
                             button_height*5 );
    }
    else
    {
        latLonLabel->move( button_width,
                           height() - latLonLabel->height() );
    }
}

void TrackTable::updateMatrix()
{
    // This is the new scaled size, in lon/lat, this time...
    // (this is how much you can see on the screen)
    double area_size_width = ((double)width()) / (screen_scale*longitude_correction);
    double area_size_height = ((double)height()) /screen_scale;

    // NOTE: all the cohordinates are ALWAYS expressed in logical lat/lon. Screen (pixel) cohordinates
    //       are converted multiplying them with the matrix. The "visible area" is the portion of the
    //       lat/lon world which will be visible on the device screen.

    // When "inverting" the vertical ax, we must calculate two different offsets.
    // This is the top/left corner of the visible area rect:
    double area_corner_x = screen_longitude - area_size_width/2.0;
    double area_corner_y = screen_latitude - area_size_height/2.0;

    // This is the rectangle "visible" on the screen. Anything outside, is not visible and will be clipped.
    // We calculate this here so that layers can speed up by checking if they are inside the visible area
    // or not...
    wgs84_visible_rect.setRect(area_corner_x, area_corner_y, area_size_width, area_size_height );

    // Apply the transform to the matrix
    wgs84_to_screen_matrix.reset();
    wgs84_to_screen_matrix.scale( (double)(screen_scale*longitude_correction), -screen_scale );
    // The translation offset must be referred to the bottom/left corner of the visible area:
    wgs84_to_screen_matrix.translate( -(area_corner_x), -(area_corner_y + area_size_height) );

    update();
}
